#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QPushButton>
#include "graph.h"
#include <time.h>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    cap=new capture(this);
    yolov3Net=new yolov3;
    graphWindow=new graph(ui->frame);
    connectEvents();
    ui->listWidget->setViewMode(QListView::IconMode);
    ui->listWidget->setIconSize(QSize(110,110));
    ui->listWidget->setMovement(QListView::Static);
    ui->window->setPixmap(QPixmap("res\\pre.jpg"));
    setting = nullptr;
    preimg = cv::imread("res\\pre.jpg");
}

void MainWindow::connectEvents()
{
    connect(ui->run,&QPushButton::clicked,[=](){
        if(!cap->timer->isActive())
        {
            emit cap->start();
        }
        else
        {
            emit cap->stop();
        }

    });
    connect(cap,&capture::stop,[=](){
        ui->run->setText("继续");
    });
    connect(cap,&capture::start,[=](){
        ui->run->setText("暂停");
    });
    connect(cap,&capture::switchSource,[=](){
        ui->run->setText("开始");
        labelDisplayMat(ui->window,*cap->readFrame());
    });
    connect(cap->timer,&QTimer::timeout,this,&MainWindow::detect,Qt::DirectConnection);
    connect(ui->camera,&QPushButton::clicked,[=](){
        cap->openCamera();
    });
    connect(ui->localVideo,&QPushButton::clicked,[=](){
        cap->openVideo();
    });
    connect(yolov3Net,SIGNAL(violation(cv::Mat)),this,SLOT(showViolationLists(cv::Mat)));

    connect(ui->setButton,&QPushButton::clicked,[=](){
        setting = new SetDialog(nullptr,yolov3Net->getmodelCfg(),yolov3Net->getmodelWeights(),yolov3Net->getClassesFile(),yolov3Net->getConfidence());
        connect(setting,SIGNAL(changeCfg(QString)),this,SLOT(changeCfg(QString)));
        connect(setting,SIGNAL(changeName(QString)),this,SLOT(changeName(QString)));
        connect(setting,SIGNAL(changeWeight(QString)),this,SLOT(changeWeight(QString)));
        connect(setting,SIGNAL(changeConfidence(double)),this,SLOT(changeConfidence(double)));
        connect(setting,SIGNAL(ensure()),this,SLOT(modifyNet()));
        setting->exec();
        //        setting->show();
    });
}


void MainWindow::detect()
{
    static QTime Time(QTime::currentTime());
    double key = Time.elapsed()/1000.0;
    time_t start,end;
    start=clock();
    labelDisplayMat(ui->window,*cap->readFrame());
    end=clock();
    graphWindow->updateGraph(key,1/((double)(end-start)/CLOCKS_PER_SEC));
}
//void MainWindow::transformMatToImage(cv::Mat& mat,QImage& Img)
//{
//    cv::Mat Rgb;
//    if (mat.channels() == 3)//RGB Img
//    {
//        cv::cvtColor(mat, Rgb, CV_BGR2RGB);//颜色空间转换
//        Img = QImage((const uchar*)(Rgb.data), Rgb.cols, Rgb.rows, Rgb.cols * Rgb.channels(), QImage::Format_RGB888);
//    }
//    else//Gray Img
//    {
//        Img = QImage((const uchar*)(mat.data), mat.cols, mat.rows, mat.cols*mat.channels(), QImage::Format_Indexed8);
//    }
//}
void MainWindow::labelDisplayMat(QLabel *label, cv::Mat &mat)
{
    mat= yolov3Net->detect(&mat);

    cv::Mat Rgb;
    QImage Img;
    if (mat.channels() == 3)//RGB Img
    {
        cv::cvtColor(mat, Rgb, cv::COLOR_BGR2RGB);//颜色空间转换
        Img = QImage((const uchar*)(Rgb.data), Rgb.cols, Rgb.rows, Rgb.cols * Rgb.channels(), QImage::Format_RGB888);
    }
    else//Gray Img
    {
        Img = QImage((const uchar*)(mat.data), mat.cols, mat.rows, mat.cols*mat.channels(), QImage::Format_Indexed8);
    }
    //    label->resize(500,500);
    Img.scaled(label->size(),Qt::KeepAspectRatio);
    label->setScaledContents(true);
    label->setPixmap(QPixmap::fromImage(Img));
    label->update();
}

//平均哈希算法计算两幅图像的相似度
double MainWindow::ImageSimilarity(const cv::Mat &matSrc1,const cv::Mat &matSrc2)
{
    cv::Mat matDst1, matDst2;
    cv::resize(matSrc1, matDst1, cv::Size(8, 8), 0, 0, cv::INTER_CUBIC);
    cv::resize(matSrc2, matDst2, cv::Size(8, 8), 0, 0, cv::INTER_CUBIC);

    cv::cvtColor(matDst1, matDst1, cv::COLOR_BGR2GRAY);
    cv::cvtColor(matDst2, matDst2, cv::COLOR_BGR2GRAY);

    int iAvg1 = 0, iAvg2 = 0;
    int arr1[64], arr2[64];

    for (int i = 0; i < 8; i++)
    {
        uchar* data1 = matDst1.ptr<uchar>(i);
        uchar* data2 = matDst2.ptr<uchar>(i);

        int tmp = i * 8;

        for (int j = 0; j < 8; j++)
        {
            int tmp1 = tmp + j;

            arr1[tmp1] = data1[j] / 4 * 4;
            arr2[tmp1] = data2[j] / 4 * 4;

            iAvg1 += arr1[tmp1];
            iAvg2 += arr2[tmp1];
        }
    }

    iAvg1 /= 64;
    iAvg2 /= 64;

    for (int i = 0; i < 64; i++)
    {
        arr1[i] = (arr1[i] >= iAvg1) ? 1 : 0;
        arr2[i] = (arr2[i] >= iAvg2) ? 1 : 0;
    }

    double iDiffNum = 0;

    for (int i = 0; i < 64; i++)
        if (arr1[i] == arr2[i])
            ++iDiffNum;

    return iDiffNum/64;
}
void MainWindow::showViolationLists(cv::Mat mat)
{
    cv::Mat Rgb;
    if(0.999<=  ImageSimilarity(preimg,mat))
    {
        return;
    }
    preimg = mat;
    QImage Img;
    if (mat.channels() == 3)//RGB Img
    {
        cv::cvtColor(mat, Rgb, cv::COLOR_BGR2RGB);//颜色空间转换
        Img = QImage((const uchar*)(Rgb.data), Rgb.cols, Rgb.rows, Rgb.cols * Rgb.channels(), QImage::Format_RGB888);
    }
    else//Gray Img
    {
        Img = QImage((const uchar*)(mat.data), mat.cols, mat.rows, mat.cols*mat.channels(), QImage::Format_Indexed8);
    }
    QListWidgetItem *imageItem = new QListWidgetItem;
    imageItem->setIcon(QIcon(QPixmap::fromImage(Img)));
    ui->listWidget->addItem(imageItem);
    ui->listWidget->update();
    connect(ui->listWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(showPic(QListWidgetItem*)));
    static int violationNumber=0;
    violationNumber++;
    if(violationNumber==100)
    {
        violationNumber=0;
        ui->listWidget->clear();
    }
}
void MainWindow::showPic(QListWidgetItem* ite)
{
    emit cap->stop();
    ui->window->setPixmap(ite->icon().pixmap(ui->window->size()));
    //    ui->run->setEnabled(false);
}
void MainWindow::changeCfg(QString cfg)
{
    this->cfgString=cfg;
}
void MainWindow::changeName(QString name)
{
    this->nameString= name;
}
void MainWindow::changeWeight(QString weight)
{
    this->weightString=weight;
}
void MainWindow::changeConfidence(double confidence)
{
    this->confidence=confidence;
}
void MainWindow::modifyNet()
{
//    emit cap->stop();
    yolov3Net->modifyNet(cfgString,nameString,weightString,confidence);
//    emit cap->start();
}
MainWindow::~MainWindow()
{
    delete ui;
    delete graphWindow;
}
